﻿/*   
    Copyright (C) 2009 Galaktika Corporation ZAO

    This file is a part of Galaktika.BusinessMonitor
 
    Galaktika.BusinessMonitor is a free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
      
    You should have received a copy of the GNU General Public License
    along with Galaktika.BusinessMonitor.  If not, see <http://www.gnu.org/licenses/>.
  
    If GPL v.3 is not suitable for your products or company,
    Galaktika Corp provides Galaktika.BusinessMonitor under a flexible commercial license
    designed to meet your specific usage and distribution requirements.
    If you have already obtained a commercial license from Galaktika Corp,
    you can use this file under those license terms.
*/

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace Galaktika.BI.Silverlight.ClientApp
{
    using Galaktika.BI.Runtime;
    using Galaktika.BI.Runtime.Services;
    using Galaktika.BI.Silverlight.ClientApp.Items;
    using Galaktika.BI.Silverlight.Controls;
    using Galaktika.BI.Extensibility.Dom;

    public partial class FormView : UserControl, IBrickContainerHolder
    {
        public class BindableVariableCollection : IEnumerable
        {
            private Dispatcher m_Disp;
            private IEnumerable<BrickVariable> m_Vars;
            //private List<BindableVariable> m_Enumerable;

            public BindableVariableCollection(
                IEnumerable<BrickVariable> vars,
                Dispatcher disp)
            {
                m_Vars = vars;
                m_Disp = disp;
                //m_Enumerable = new List<BindableVariable>();
            }

            #region IEnumerable Members
            public IEnumerator GetEnumerator()
            {
                foreach (var v in m_Vars)
                {
                    yield return new BindableVariable(v, m_Disp);
                }
            }
            #endregion
        }

        public class BindableVariable : INotifyPropertyChanged
        {
            private BrickVariable m_Var;
            private Dispatcher m_Disp;

            public BindableVariable(
                BrickVariable var,
                Dispatcher disp)
            {
                m_Var = var;
                m_Disp = disp;
                m_Var.PropertyChanged += m_Var_PropertyChanged;
            }

            ~BindableVariable()
            {
                m_Var.PropertyChanged -= m_Var_PropertyChanged;
            }

            void m_Var_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                this.OnPropertyChanged(e.PropertyName);
            }

            public string Name
            {
                get
                {
                    return m_Var.Name;
                }
            }

            public string CurrentValue
            {
                get
                {
                    return m_Var.CurrentValue;
                }
            }

            #region INotifyPropertyChanged Members

            public event PropertyChangedEventHandler PropertyChanged;
            protected void OnPropertyChanged(string propertyName)
            {
                var handler = this.PropertyChanged;
                if (handler != null)
                {
                    m_Disp.BeginInvoke(() => handler(this, new PropertyChangedEventArgs(propertyName)));
                }
            }

            #endregion
        }

        public FormView()
        {
            InitializeComponent();

            expanderWindows.ExpandChanged += new EventHandler(expanderWindows_ExpandChanged);
            colContextWindowSplitter.Width = new GridLength(0.0);

            expanderWindows.SetButtonTooltip(new StyledToolTip() { Content = Localization.Tooltip_ContextWindows });
            expanderWindows.HeaderWidth = new GridLength(0.0);

            expVars.ExpandChanged += new EventHandler(expVars_ExpandChanged);
            colVarsSplitter.Width = new GridLength(0.0);

            expVars.SetButtonTooltip(new StyledToolTip() { Content = Localization.Tooltip_Variables });
            expVars.HeaderWidth = new GridLength(0.0);

            //grdVars.IsReadOnly = true;
            grdVars.Columns.Add(new DataGridTextColumn() { Binding = new Binding("Name") { Mode = BindingMode.OneWay }, Header = Localization.Str_Caption, IsReadOnly = true });
            grdVars.Columns.Add(new DataGridTextColumn() { Binding = new Binding("CurrentValue") { Mode = BindingMode.TwoWay }, Header = Localization.Str_Value });
        }

        void expVars_ExpandChanged(object sender, EventArgs e)
        {
            if (expVars.IsExpanded)
            {
                if (grdVars.ItemsSource == null)
                {
                    var context = App.CurrentApp.Binder.GetContext(this);
                    if (context != null)
                    {
                        var vars = App.CurrentApp.Binder.GetVariables(context);
                        grdVars.ItemsSource = new BindableVariableCollection(vars.Variables, this.Dispatcher);
                    }
                }

                colVarsSplitter.Width = GridLength.Auto;
            }
            else
            {
                colVarsSplitter.Width = new GridLength(0.0);
            }
        }

        private IDictionary<string, IDataManager> m_DataManagerCache = null;
        private bool isContextWindowsLoaded;

        void expanderWindows_ExpandChanged(object sender, EventArgs e)
        {
            if (expanderWindows.IsExpanded)
            {
                colContextWindowSplitter.Width = GridLength.Auto;
                var context = App.CurrentApp.Binder.GetContext(this);
                if (!isContextWindowsLoaded)
                    this.InitializeContextWindows(context, m_DataManagerCache);
                isContextWindowsLoaded = true;
            }
            else
            {
                colContextWindowSplitter.Width = new GridLength(0.0);
            }
        }

        IBrickContainer m_Container;
        public IBrickContainer Container
        {
            get
            {
                return m_Container;
            }
        }

        public bool HasContextWindows
        {
            get
            {
                return m_ContextWindows.Count > 0;
            }
        }

        public bool IsContextWindowsVisible
        {
            get
            {
                return expanderWindows.IsExpanded;
            }
            set
            {
                expanderWindows.IsExpanded = value;
            }
        }

        public bool IsVariablesVisible
        {
            get
            {
                return expVars.IsExpanded;
            }
            set
            {
                expVars.IsExpanded = value;
            }
        }

        private FrameworkElement m_BusyPresenter;

        public bool IsBusy
        {
            get
            {
                return m_BusyPresenter != null;
            }
        }

        private void CreateBusyPresenter()
        {
            var b = new Canvas();
            b.HorizontalAlignment = HorizontalAlignment.Stretch;
            b.VerticalAlignment = VerticalAlignment.Stretch;
            b.Background = new SolidColorBrush(Colors.Transparent);
            m_BusyPresenter = b;
            gridContainer.Children.Add(m_BusyPresenter);
            b.Cursor = Cursors.Wait;
        }

        private void DeleteBusyPresenter()
        {
            m_BusyPresenter.Cursor = Cursors.Arrow;
            gridContainer.Children.Remove(m_BusyPresenter);
            m_BusyPresenter = null;
        }

        public void SwitchToBusyState()
        {
            m_ContextWindows.ForEach(f => f.SwitchToBusyState());
            if (!this.IsBusy)
            {
                this.CreateBusyPresenter();
            }
            //this.Layout.IsEnabled = false;
        }

        public void SwitchToFreeState()
        {
            m_ContextWindows.ForEach(f => f.SwitchToFreeState());
            if (this.IsBusy)
            {
                this.DeleteBusyPresenter();
            }
        }

        public void Initialize(IBrickContainer container)
        {
            this.Initialize(
                container,
                null,
                new Dictionary<string, IDataManager>());
        }

        private void Initialize(
            IBrickContainer container,
            IBindingContext context,
            IDictionary<string, IDataManager> dataManagerCache)
        {
            // Если context == null - значит в container находится основная форма.
            // Иначе в container находится контекстное окно, а в context -
            // контекст основной формы.
            bool isMainForm = context == null;

            base.Name = container.Name;
            m_Container = container;

            this.Layout.LoadLayout(container.Layout, !isMainForm);

            foreach (UIElement obj in container.Controls)
            {
                this.Layout.AddElement(obj);
            }

            foreach (UIElement template in this.CreateTemplates(container, context, dataManagerCache))
            {
                this.Layout.AddElement(template);
            }


            if (isMainForm)
            {
                // в container находится основная форма
                App.CurrentApp.Binder.Bind(this, container, dataManagerCache);
                m_DataManagerCache = dataManagerCache;
                isContextWindowsLoaded = false;
                IsContextWindowsVisible = false;
                //context = App.CurrentApp.Binder.GetContext(this);
                //this.InitializeContextWindows(context, dataManagerCache);
            }
            else
            {
                expanderWindows.Visibility = Visibility.Collapsed;
                // иначе контекстное окно
                App.CurrentApp.Binder.BindInternal(this, container, context, dataManagerCache);
            }
        }

        private IEnumerable<UIElement> CreateTemplates(
            IBrickContainer container,
            IBindingContext context,
            IDictionary<string, IDataManager> dataManagerCache)
        {
            var templates = container.Templates;
            List<UIElement> res = new List<UIElement>(templates.Length);
            foreach (var template in templates)
            {
                var templateForm = new FormView()
                {
                    Id = this.Id,
                    Name = template.Name
                };
                templateForm.Initialize(template, context, dataManagerCache);
                res.Add(templateForm);
            }

            return res;
        }

        private void InitializeContextWindows(IBindingContext context, IDictionary<string, IDataManager> dataManagerCache)
        {
            int i = 0;
            IEnumerable<string> wndIds = App.CurrentApp.Binder.GetContextWindows(this.Id);
            m_ContextWindows.Clear();
            ctxWindows.UnselectAll();
            ctxWindows.Items.Clear();
            foreach (string contextWindowId in wndIds)
            {
                IBrickContainer context_Container = ClientResources.GetContainer(contextWindowId);
                FormView contextForm = new FormView();
                contextForm.Layout.IsScalable = true;
                contextForm.VerticalAlignment = VerticalAlignment.Stretch;
                contextForm.HorizontalAlignment = HorizontalAlignment.Stretch;
                contextForm.Id = contextWindowId;
                contextForm.Initialize(context_Container, context, dataManagerCache);

                if (!this.m_ContextWindows.Contains(contextForm))
                    this.m_ContextWindows.Add(contextForm);
                if (context != null)
                {
                    App.CurrentApp.Binder.RefreshImmediate(context_Container, context);
                }

                AccordionItem item = new SizeableAccordionItem();
                item.Header = context_Container.Title;
                item.Content = contextForm;

                var p = from ctx in ctxWindows.Items
                        where (ctx as SizeableAccordionItem).Header.ToString().Equals(item.Header)
                        select ctx;
                if (p.Count() == 0)
                    ctxWindows.Items.Add(item);


                i++;
            }           

            if (i == 0)
            {
                colContextWindow.Width = colContextWindowSplitter.Width = new GridLength(0.0);
            }
                
        }

        public string Id { get; set; }
        public string UniqueId
        {
            get
            {
                return this.GetHashCode().ToString();
            }
        }

        public string Text
        {
            get
            {
                return m_Container.Title;
            }
        }

        private List<FormView> m_ContextWindows = new List<FormView>();
        public List<FormView> ContextWindows
        {
            get
            {
                return m_ContextWindows;
            }
        }

        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {

        }
    }

    public class SizeableAccordionItem : AccordionItem
    {
        public SizeableAccordionItem()
        {
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            ExpandableContentControl site = base.GetTemplateChild("ExpandSite") as ExpandableContentControl;
            if (site != null)
            {
                //site.HorizontalContentAlignment = HorizontalAlignment.Stretch;
                site.VerticalContentAlignment = System.Windows.VerticalAlignment.Stretch;
            }
        }
    }
}
